﻿Public Class ExplorerTreeList
    Implements IReloadCommand

    ''' <summary>
    ''' TreeList.FindNodeByID -- allows you to find the node by the data record index in the datasource;
    '''TreeList.FindNodeByKeyID -- allows you to find the node by the unique key value, that is the value of the field defined as the TreeList.KeyFieldName property;
    '''TreeList.FindNodeByFieldValue -- returns the first found node with the specified column value.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>


    Private Property _BreadCrumb As String

    Public AQueryList As Dictionary(Of String, String) = New Dictionary(Of String, String)

    Public Property MainMetaQuery As MetaQuery
    Public Property QueryName() As String
    Public Property KeyFieldName() As String
    Public Property ParentFieldName() As String
    Public Property MetaControlTreeListActionOptionList() As CommonExt.Base.ActionOptionList
    Public Property DefaultTreeListActionOptionList() As CommonExt.Base.ActionOptionList
    Public Property TreeContextMenu As TreeListMenu
    Public Property DataSrc As DataTable
    Public Property PL As PL.PLBase
    Public Property PanelName() As String Implements IReloadCommand.CtrlName
    Public Property LastFocusedNode As TreeListNode
    Public Property CurrentFocusedNode As TreeListNode
    Public Property NodeDataRow As DataRow
    Public Property FocusedNodeLevel As Integer
    Public Property aChildQueryToDisplay As DataTable = Nothing

    Public Property Selection As TreeListMultiSelection
        Get
            Selection = TreeList1.Selection
        End Get
        Set(value As TreeListMultiSelection)
            TreeList1.Selection.Set(value)
        End Set
    End Property


    Public Enum ReloadContext
        AfterDelete = 5
        AfterUpdate = 1

    End Enum


    Public ReadOnly Property BreadCrumbText As String
        Get
            Return _BreadCrumb
        End Get
    End Property

    'Public Event InitTreeActionOptionList(ByVal sender As Object, ByVal e As EventArgs)


    Public Property ArchiveIncluded As Boolean = False
    '
    Public Property ArchiveField As String
    Public Property ArchiveTable As String
    Public Property ArchiveId As Guid
    Private Property Secure As Boolean
    Private lastXdays As Integer? = Nothing
    Private fromCrtDt As String = Nothing     ' Private variable assign from lastXdays , used in MergeMetaQueryResult
    Public ExplorerName As String = String.Empty

    Public WithEvents aGridControl As GridExtPL

    Public WithEvents aGridLayout As GridLayoutPL

    Public Event NodeContextMenuBeforePopup(sender As Object, e As DevExpress.XtraTreeList.PopupMenuShowingEventArgs)



    Private explorerTreeListState As ExplorerTreeListState
    Private _hitInfo As TreeListHitInfo

    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()
        TreeList1.ForceInitialize()
        TreeList1.OptionsView.AutoWidth = False
        TreeList1.OptionsView.ShowColumns = True
        _BreadCrumb = Nothing
        explorerTreeListState = New ExplorerTreeListState(TreeList1)
        Me.ExplorerName = Me.GetType.Name
    End Sub

    Public Sub New(ByVal aQueryname As String, Optional ByVal SecureExplorer As Boolean = False)
        Me.New()
        QueryName = aQueryname
        Secure = SecureExplorer
    End Sub

    Private Sub ContextMenuCollapseAll(ByVal sender As Object, ByVal e As EventArgs)
        Dim aNode As TreeListNode = TreeList1.FocusedNode
        ' Let capture the node and expand the branch.
        For Each n As TreeListNode In aNode.Nodes
            n.Expanded = False
        Next n
    End Sub

    Private Sub ContextMenuCollapseAll2(ByVal sender As Object, ByVal e As EventArgs)
        TreeList1.CollapseAll()
    End Sub

    Private Sub ContextMenuExpandAll(ByVal sender As Object, ByVal e As EventArgs)
        Dim aNode As TreeListNode = TreeList1.FocusedNode
        ' Let capture the node and expand the branch.
        For Each n As TreeListNode In aNode.Nodes
            n.Expanded = True
        Next n
    End Sub

    Private Sub ContextMenuReload(ByVal sender As Object, ByVal e As EventArgs)
        ReloadTree()
    End Sub
    ''' <summary>
    ''' This routine will read the Metacontrol Props of Explorer Control property 'LastXdays'.
    ''' </summary>
    ''' <remarks>The LastXdays props value is a string. This string is to be convert into a double data type in lieu to function adecatly .
    ''' that double converted  value is then substracted from the current date and set the fromCrtDt
    ''' lastXdays variable is set and used in routines to set dates accordingly
    ''' fromCrtDt variable is et and used primerly in Mergedata to prevent unnessary recalculation from initialisation   </remarks>
    Private Sub SetLastXdays()
        Dim aControlprops As DataView
        Dim result As Integer
        aControlprops = (From oControl In AppManager.DataSubjectAccess.AsEnumerable() _
                                Where oControl.Field(Of String)("ControlName") = ExplorerName _
                                And oControl.Field(Of String)("Class") = "EXP" _
                                And oControl.Field(Of String)("Property") = "LastXdays"
                                Select oControl).AsDataView()

        If aControlprops.Count = 1 AndAlso Integer.TryParse(aControlprops.Item(0).Row("Value").ToString(), result) Then
            If result > 0 Then
                Me.lastXdays = result
                fromCrtDt = Date.Now.AddDays(CDbl(-(lastXdays))).ToString("yyyy/MM/dd")
            End If
        End If


    End Sub

    Public Sub ReloadTree(context As ReloadContext)
        Me.Cursor = Cursors.WaitCursor
        Dim activeFilter As String = TreeList1.ActiveFilterString
        Select Case context
            Case ReloadContext.AfterDelete
                Dim anode As TreeListNode = TreeList1.FocusedNode.ParentNode
                TreeList1.FocusedNode = anode
                explorerTreeListState.SaveState()
                AQueryList.Clear()
                TreeList1.DataSource = Nothing
                TreeList1.ClearColumnsFilter()
                InitData()
                TreeList1.ActiveFilterString = activeFilter
                explorerTreeListState.LoadState()

            Case ReloadContext.AfterUpdate
                Dim anode As TreeListNode = TreeList1.FocusedNode

                explorerTreeListState.SaveState()
                AQueryList.Clear()
                TreeList1.DataSource = Nothing
                TreeList1.ClearColumnsFilter()
                InitData()
                TreeList1.ActiveFilterString = activeFilter
                explorerTreeListState.LoadState()
                TreeList1.FocusedNode = anode


        End Select
        'Dim posKeyID As Guid = CType(CType(TreeList1.GetDataRecordByNode(TreeList1.FocusedNode), DataRow)("KeyID"), Guid)
        Me.Cursor = Cursors.Default
    End Sub


    Public Sub ReloadTree() Implements CommonExt.IReloadCommand.ReloadCommand
        Me.Cursor = Cursors.WaitCursor
        Dim activeFilter As String = TreeList1.ActiveFilterString
        'Dim posKeyID As Guid = CType(CType(TreeList1.GetDataRecordByNode(TreeList1.FocusedNode), DataRow)("KeyID"), Guid)
        explorerTreeListState.SaveState()
        AQueryList.Clear()
        TreeList1.DataSource = Nothing
        TreeList1.ClearColumnsFilter()
        InitData()
        TreeList1.ActiveFilterString = activeFilter
        explorerTreeListState.LoadState()
        Me.Cursor = Cursors.Default
    End Sub

    Private Sub ContextMenuExportToExcel(ByVal sender As Object, ByVal e As EventArgs)
        Dim filename As String
        Me.Cursor = Cursors.WaitCursor
        Try
            filename = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), TreeList1.Tag.ToString)
            Using aFile As New System.Windows.Forms.SaveFileDialog
                aFile.DefaultExt = "xls"
                aFile.FileName = filename
                aFile.AutoUpgradeEnabled = True
                If aFile.ShowDialog() = DialogResult.OK Then

                    TreeList1.OptionsPrint.AutoWidth = False
                    TreeList1.OptionsPrint.PrintAllNodes = True
                    TreeList1.OptionsPrint.PrintFilledTreeIndent = True
                    TreeList1.OptionsPrint.PrintTreeButtons = False
                    TreeList1.ExportToXls(aFile.FileName)

                    MessageWindow.ShowMessage(String.Format("Export To Excel Succesfull.{0}{0}Your Filename is: {1}", vbCrLf, aFile.FileName), MsgBoxStyle.Information)

                End If
            End Using
        Catch ex As Exception
            Throw ex
        End Try
        Me.Cursor = Cursors.Default
    End Sub
    ''' <summary>
    ''' This Subroutine load and initialise standard bydesign Action for the TreelistExt of AcitiveFramework.
    ''' this is where DefaultActionOptionList contructor is called 
    ''' this is where MetaControlActionOptionList contructor is called 
    ''' </summary>
    ''' <remarks>
    ''' Also the security from MetaUserControlProp is applied.
    ''' Remember to perform a "Refresh user Profile" if user proifle has been modified   ''' 
    ''' </remarks>
    Public Overridable Sub ActionOptionLoad()
        Dim act As CommonExt.Base.ActionOption

        MetaControlTreeListActionOptionList = New CommonExt.Base.ActionOptionList()

        DefaultTreeListActionOptionList = New CommonExt.Base.ActionOptionList()
        act = New CommonExt.Base.ActionOption("TreeOption", "ACT_00167", "Reload Data", AddressOf ContextMenuReload, True, True)
        DefaultTreeListActionOptionList.Add(act)
        act = New CommonExt.Base.ActionOption("TreeOption", "ACT_00168", "Export to Excel", AddressOf ContextMenuExportToExcel, True, True)
        DefaultTreeListActionOptionList.Add(act)
        act = New CommonExt.Base.ActionOption("TreeOption2", "ACT_00169", "Collaps All", AddressOf ContextMenuCollapseAll, True, True)
        DefaultTreeListActionOptionList.Add(act)
        act = New CommonExt.Base.ActionOption("TreeOption2", "ACT_00170", "Expand All", AddressOf ContextMenuExpandAll, True, True)
        DefaultTreeListActionOptionList.Add(act)


        SetLastXdays()
        If lastXdays IsNot Nothing Then
            act = New CommonExt.Base.ActionOption("TreeOption3", "LastXXDays", String.Format("Last {0} days", lastXdays), AddressOf ContextMenuLastXxDays, True, True)
            DefaultTreeListActionOptionList.Add(act)
            act = New CommonExt.Base.ActionOption("TreeOption3", "AllData", "All Data With Archive", AddressOf ContextMenuAllData, True, True)
            DefaultTreeListActionOptionList.Add(act)
        End If


        DefaultTreeListActionOptionList.ApplySecurity()

    End Sub
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ContextMenuLastXxDays(ByVal sender As System.Object, ByVal e As EventArgs)
        fromCrtDt = Date.Now.AddDays(CDbl(-(lastXdays))).ToString("yyyy/MM/dd")
        Me.ArchiveIncluded = False
        ReloadTree()
    End Sub
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ContextMenuAllData(ByVal sender As System.Object, ByVal e As EventArgs)
        fromCrtDt = Nothing
        Me.ArchiveIncluded = True
        ReloadTree()
    End Sub

    ''' <summary>
    ''' This Sub will load in the ContextMenu of the Treelist of all define defaut action by design.
    ''' </summary>
    ''' <remarks>
    ''' DefaultActionOptionList is filled by Overridable Sub ActionOptionLoad()
    ''' Then it will Load all context menu define in MetaControlActionOptionList
    ''' MetaControlActionOptionList is the context list of action that you can load by your consumer.
    ''' Load your consumer with MetaControlActionOptionList.Add(action) where action is an ActionOption object of the Active framework
    ''' Usage of the Overrides Sub ActionOptionLoad() in your consumer to manage all of your context menu is a recommneded design pattern.
    ''' 
    ''' </remarks>
    Public Overridable Sub LoadContextMenu()
        Dim item As DXMenuItem
        Dim grpName As String = String.Empty
        Dim intNodeLevel As Integer


        'Beton
        TreeContextMenu = New DevExpress.XtraTreeList.Menu.TreeListMenu(TreeList1)
        For Each action As CommonExt.Base.ActionOption In DefaultTreeListActionOptionList
            item = New DXMenuItem(action.OptionTitle, action.EventHandler, Nothing)
            item.Enabled = action.Enabled
            item.Tag = action
            'Add new Group Separator when Group Name change
            If (grpName <> action.OptionGroup And grpName <> String.Empty) Then
                item.BeginGroup = True
            End If
            grpName = action.OptionGroup
            TreeContextMenu.Items.Add(item)
        Next


        'Toe stie
        If NodeDataRow IsNot Nothing Then
            For Each action As CommonExt.Base.ActionOption In MetaControlTreeListActionOptionList
                item = New DXMenuItem(action.OptionTitle, action.EventHandler, Nothing)
                item.Enabled = action.Enabled
                item.Visible = action.Visible
                item.Tag = action
                'Add new Group Separator when Group Name change
                If (grpName <> action.OptionGroup And grpName <> String.Empty) Then
                    item.BeginGroup = True
                End If
                grpName = action.OptionGroup

                If Not Integer.TryParse(action.IndentLevelReference, intNodeLevel) Then ' this is how we check if Action has a level number  or query name as parameter
                    If String.IsNullOrEmpty(action.IndentLevelReference) OrElse NodeDataRow("MetaQuerie").ToString = action.IndentLevelReference Then
                        TreeContextMenu.Items.Add(item)
                    End If
                Else
                    If String.IsNullOrEmpty(action.IndentLevelReference) OrElse FocusedNodeLevel.ToString() = action.IndentLevelReference Then
                        TreeContextMenu.Items.Add(item)
                    End If
                End If

            Next
        End If
    End Sub



    Public Overridable Sub MergeMetaQueryResult()
        Dim aChildMQ As MetaQuery = Nothing

        Try
            MainMetaQuery = MetaQuery.GetMetaQueryByName(QueryName)
            If MainMetaQuery IsNot Nothing Then
                MainMetaQuery.FillResultQuery()
                'arow = MainMetaQuery.ResultQuery.Rows(0)
                'arow(3) = MainMetaQuery.Caption
                DataSrc = MainMetaQuery.ResultQuery
                AQueryList.Add(QueryName, "0")
                aChildQueryToDisplay = MainMetaQuery.GetChildDisplayQuery()

                If aChildQueryToDisplay IsNot Nothing Then
                    For Each row As DataRow In aChildQueryToDisplay.Rows
                        AQueryList.Add(row("Queryname").ToString, row("MetaqueryLevel").ToString)
                        aChildMQ = MetaQuery.GetMetaQueryByName(row("QueryName").ToString)
                        If aChildMQ IsNot Nothing Then
                            If Not String.IsNullOrEmpty(fromCrtDt) Then
                                aChildMQ.SQLWhereContext = String.Format("{0}.Crtd_DT >= '{1}'", aChildMQ.UniqueTable, fromCrtDt)
                                'OUSTANDINGISSUE: filtrer sur aChildMQ.UniqueTable
                                'pourrait amener un bug(un child sans parent) dans le cas que le parent est créer après le child dans le temps
                                ' ex: Child 2010-10-01, 11:32:36    Parent  2010-10-01 11:33:51
                            End If
                        End If


                        If Me.ArchiveIncluded = False AndAlso Me.ArchiveId <> Guid.Empty Then
                            If Not String.IsNullOrWhiteSpace(aChildMQ.SQLWhereContext) Then
                                aChildMQ.SQLWhereContext += " AND "
                            End If
                            aChildMQ.SQLWhereContext += String.Format("{0} <> '{1}'", Me.ArchiveField, Me.ArchiveId)
                        End If

                        aChildMQ.FillResultQuery()

                        If aChildMQ.ResultQuery.Rows.Count > 0 Then
                            DataSrc.Merge(aChildMQ.ResultQuery, False, MissingSchemaAction.Ignore)
                        End If


                    Next
                End If
            Else
                MessageWindow.ShowMessage(String.Format("refer to administrator , MetaQuery < {0} > is not functionning as expected ", QueryName), MsgBoxStyle.Exclamation)

            End If
        Catch ex As Exception
            MessageWindow.ShowMessage(ex, MsgBoxStyle.Information)
        End Try
    End Sub

    Public Overridable Sub InitData()
        Dim hideCol As Boolean
        Dim colname As String
        Dim Column As DevExpress.XtraTreeList.Columns.TreeListColumn
        Dim colVisible As Boolean

        TreeList1.BeginUpdate()
        '
        MergeMetaQueryResult()
        '
        'Ici on fait la security
        If Secure Then
            Dim dt As DataTable = SystemBoxSDK.PL.MetaSDK.SecurityProfiler_PL.SecurityProfileDS.Tables("DataSubjectSecurity")
            Dim aControlprops As DataView
            Dim i As Integer = DataSrc.Rows.Count - 1


            'For Each arow As DataRow In DataSrc.Rows
            '    Console.WriteLine(arow.Item("Secure_MetaControl").ToString)
            'Next

            Do While i >= 0
                Dim row As DataRow = DataSrc.Rows(i)

                If row.Table.Columns.Contains("Secure_MetaControl") = True Then
                    Dim metaControlCD As String = row.Item("Secure_MetaControl").ToString

                    aControlprops = (From oControl In dt.AsEnumerable() _
                          Where oControl.Field(Of String)("ControlCD") = metaControlCD _
                                And oControl.Field(Of String)("Property") = "AllowExecute" _
                                And oControl.Field(Of String)("VALUE") = "1"
                             Select oControl).AsDataView()

                    If aControlprops.Count = 0 And metaControlCD <> "Root" Then
                        DataSrc.Rows.RemoveAt(i)
                    End If
                End If

                i -= 1
            Loop
        End If


        '
        TreeList1.KeyFieldName = KeyFieldName
        TreeList1.ParentFieldName = ParentFieldName
        TreeList1.DataSource = DataSrc
        TreeList1.Tag = MainMetaQuery
        '
        TreeList1.OptionsBehavior.EnableFiltering = True
        TreeList1.Columns.Clear()
        For Each row As DataRow In MainMetaQuery.MetaColumns.Rows
            colname = row("ColumnName").ToString
            hideCol = False

            If AppManager.ApplicationOption.DescriptionColumnIndex = 2 Then
                If colname.EndsWith("_ALT") Then
                    hideCol = True
                End If
            Else
                If colname.EndsWith("_PRM") Then
                    hideCol = True
                End If
            End If
            If hideCol = False Then
                colVisible = CBool(IIf(CInt(row("pVisible")) = 0, False, True))
                Column = TreeList1.Columns.AddField(colname)
                Column.VisibleIndex = CInt(row("pOrder"))
                Column.Caption = row("pCaption").ToString

                Column.Visible = colVisible
                Column.Width = CInt(row("pWidth"))
                'Column.ToolTip = row("pToolTip").ToString

                Column.AllowIncrementalSearch = True
                Column.OptionsColumn.AllowEdit = True
                Column.OptionsColumn.ShowInCustomizationForm = True

                Column.Format.FormatType = DevExGridHelper.GetFormatType(row)
                Column.Format.FormatString = row("pNumberFormat").ToString

                Dim aSortGuid As System.Guid
                If Not IsDBNull(row("pSortByOrder")) Then
                    If CInt(row("pSortByOrder")) >= 1 AndAlso Guid.TryParse(row("pSortOrderID_FK").ToString, aSortGuid) Then
                        'By design we sort Ascending  
                        Select Case aSortGuid
                            Case IdRepository.APP_COLUMNSORTORDER_DESCENDING
                                '    columnSortInfo.Add(New GridColumnSortInfo(TreeList1.Columns(row("ColumnName").ToString), DevExpress.Data.ColumnSortOrder.Descending))

                            Case IdRepository.APP_COLUMNSORTORDER_NONE
                                '   columnSortInfo.Add(New GridColumnSortInfo(TreeList1.Columns(row("ColumnName").ToString), DevExpress.Data.ColumnSortOrder.None))

                            Case Else
                                '  columnSortInfo.Add(New GridColumnSortInfo(TreeList1.Columns(row("ColumnName").ToString), DevExpress.Data.ColumnSortOrder.Ascending))

                        End Select
                    Else
                        TreeList1.Columns(row("ColumnName").ToString).SortOrder = Windows.Forms.SortOrder.Ascending
                    End If
                    TreeList1.Columns(row("ColumnName").ToString).SortMode = ColumnSortMode.DisplayText
                    TreeList1.Columns(row("ColumnName").ToString).SortIndex = CInt(row("pSortByOrder"))
                End If
            End If
        Next
        'On expand le root par defaut
        TreeList1.Nodes(0).RootNode.Expanded = True
        TreeList1.EndUpdate()
    End Sub

    Public Overridable Sub TreeListExt_KeyUp(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp


        If e.Control And e.Alt And e.KeyCode = Keys.Q Then
            Dim message As String
            message = String.Concat("MetaQuery: ", Me.QueryName, vbCrLf)
            MessageWindow.ShowMessage(message, MsgBoxStyle.Information)
        End If

    End Sub

    Private Sub TreeListExt_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        ActionOptionLoad()
        InitData()
        TreeList1.OptionsFilter.AllowFilterEditor = False
        TreeList1.OptionsView.ShowFilterPanelMode = DevExpress.XtraTreeList.ShowFilterPanelMode.Never
        TreeList1.OptionsView.ShowSummaryFooter = True
    End Sub

    Public Overridable Sub PopulateDetailSection()

        Dim guidParent As Guid = Nothing
        Dim guidEnfant As Guid = DirectCast(NodeDataRow(Me.KeyFieldName), Guid)

        System.Guid.TryParse(NodeDataRow(Me.ParentFieldName).ToString, guidParent)
        'If node.Level > 0 Then
        '    guidParent = DirectCast(NodeDataRow(Me.ParentFieldName), Guid)
        'End If

        PL.ID = guidEnfant

        'BestPractice: To manage memory
        If aGridControl IsNot Nothing Then
            aGridControl.Dispose()
            aGridControl = Nothing
        End If
        '
        aGridControl = New GridExtPL() With {.Dock = DockStyle.Fill, .Pl = PL, .Name = ""}
        aGridControl.SecureGrid = True
        '
        'On trouve la form pour effacer les controle dedans et ensuite remettre le bon.
        'Comme ca on change le Detail selon la ligne dans L'explorer
        For Each aFrm As XtraForm In Me.ParentForm.MdiChildren
            If aFrm.Name = PanelName Then
                aFrm.Controls.Clear()
                aFrm.Controls.Add(aGridControl)
                aFrm.Text = NodeDataRow("Description_PRM").ToString()
                aFrm.Show()
                aFrm.Focus()
            End If
            aFrm.Refresh()
        Next
    End Sub

    'http://www.devexpress.com/Support/Center/Example/Details/E3902
    Private Sub OnFilterNode(ByVal sender As Object, ByVal e As FilterNodeEventArgs) Handles TreeList1.FilterNode
        Dim filteredColumns As List(Of DevExpress.XtraTreeList.Columns.TreeListColumn) = e.Node.TreeList.Columns.Cast(Of DevExpress.XtraTreeList.Columns.TreeListColumn)().Where(Function(b) b.FilterInfo.AutoFilterRowValue IsNot Nothing).ToList()
        Dim _node As TreeListNode = e.Node

        If filteredColumns.Count = 0 Then
            If TypeOf (TreeList1.FocusedNode) Is DevExpress.XtraTreeList.Nodes.TreeListAutoFilterNode AndAlso LastFocusedNode IsNot Nothing Then
                TreeList1.TopVisibleNodeIndex = TreeList1.GetVisibleIndexByNode(LastFocusedNode)
            End If
            Return
        End If
        e.Handled = True
        _node.Visible = filteredColumns.Any(Function(c) IsNodeMatchFilter(e.Node, c))
        'these three lines are to reposition the treelist from the last focused node
        If TypeOf (TreeList1.FocusedNode) Is DevExpress.XtraTreeList.Nodes.TreeListAutoFilterNode Then
            TreeList1.TopVisibleNodeIndex = TreeList1.GetVisibleIndexByNode(LastFocusedNode)
        End If
    End Sub

    'http://www.devexpress.com/Support/Center/Example/Details/E3902
    Private Shared Function IsNodeMatchFilter(ByVal node As TreeListNode, ByVal column As DevExpress.XtraTreeList.Columns.TreeListColumn) As Boolean
        Dim filterValue As String = column.FilterInfo.AutoFilterRowValue.ToString()
        ' Dim _treelist As TreeList = node.TreeList
        Dim anode As TreeListNode
        '
        If filterValue.StartsWith("*") Or filterValue.StartsWith("%") Then
            If node.GetDisplayText(column).ToLower.Contains(filterValue.ToLower.Substring(1)) Then
                Return True
            End If
        Else
            If node.GetDisplayText(column).ToLower.StartsWith(filterValue.ToLower) Then

                Return True
            End If
        End If
        '
        For Each n As TreeListNode In node.Nodes
            If IsNodeMatchFilter(n, column) Then
                n.Expanded = True
                anode = n.ParentNode
                While Not IsNothing(anode.ParentNode)
                    anode.Expanded = True
                    anode = anode.ParentNode
                End While
                Return True
            End If
        Next n

        Return False
    End Function


    ''' <summary>
    ''' Capture the position on mouse down to locate the initiale position and then the contexte of the action
    ''' Ex: colunm edge to resize
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Public Overridable Sub ExplorerTreeList_MouseDown(sender As Object, e As MouseEventArgs) Handles TreeList1.MouseDown
        _hitInfo = TreeList1.CalcHitInfo(e.Location)
    End Sub
    ''' <summary>
    ''' On mouseClick , 
    ''' NodeDataRow object is initialise with the node underlaying datarow from the datasource
    ''' on Right click the DoshowMainViewMenu is invoke.
    ''' on Left click the PopulalateDetailsection is invoked.
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks>the PopulateDetailsection is invoke when the click is position is in a cell.
    ''' </remarks>
    Public Overridable Sub ExplorerTreeList_MouseClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles TreeList1.MouseClick
        Dim hitInfo As TreeListHitInfo = TreeList1.CalcHitInfo(e.Location)
        Dim aTreeList As TreeList = CType(sender, TreeList)
        If aTreeList.FocusedNode IsNot Nothing AndAlso Not aTreeList.FocusedNode.Id.Equals(TreeList.AutoFilterNodeId) Then
            NodeDataRow = TryCast(aTreeList.GetDataRecordByNode(aTreeList.FocusedNode), DataRowView).Row
        End If

        'Test point: Ici ca va nous ramener les childs que nous avons p-e ajouter a droite sous le denier noeud que nous étions positionné. 
        If aTreeList.FocusedNode.HasChildren AndAlso aTreeList.FocusedNode.Level > 0 Then
            Dim node As TreeListNode = aTreeList.FocusedNode
            If Not node.Expanded Then
                While node.HasChildren
                    node.Expanded = True
                    node = node.FirstNode
                End While
            End If
        End If

        If e.Button = MouseButtons.Right AndAlso NodeDataRow IsNot Nothing Then
            LoadContextMenu()
            TreeContextMenu.Show(hitInfo.MousePoint)
        End If

        If e.Button = MouseButtons.Left Then
            If _hitInfo.HitInfoType = HitInfoType.Cell Then

                If NodeDataRow IsNot Nothing Then
                    Me.Cursor = Cursors.WaitCursor
                    PopulateDetailSection()
                    Me.Cursor = Cursors.Default
                End If

            End If
        End If
    End Sub

    Private Sub BestFitColumn()
        TreeList1.BeginUpdate()
        For Each col As DevExpress.XtraTreeList.Columns.TreeListColumn In TreeList1.Columns
            If col.Visible Then
                col.BestFit()
                If col.Width > 250 Then
                    col.Width = 200 'Put back value we have in MetaColumns Definition
                End If
            End If
        Next
        TreeList1.EndUpdate()
    End Sub





    Public Overridable Sub ExplorerTreeList_KeyUp(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles TreeList1.KeyUp
        Dim node As TreeListNode = TreeList1.FocusedNode
        If e.Control And e.Alt And e.KeyCode = Keys.S Then
            Me.Cursor = Cursors.WaitCursor
            BestFitColumn()
            e.Handled = True
            Me.Cursor = Cursors.Default
        End If


        If e.Control And e.Alt And e.KeyCode = Keys.Q Then
            Dim message As String = String.Format("MetaQuery: {0} ", Me.QueryName, vbCrLf)
            MessageWindow.ShowMessage(message, MsgBoxStyle.Information)
            e.Handled = True
        End If

        'Save Layout of the Focus  (XML file on computer)
        If e.Control AndAlso e.Alt AndAlso e.KeyCode = Keys.L AndAlso TreeList1.Tag IsNot Nothing Then
            Using aFile As New System.Windows.Forms.SaveFileDialog
                aFile.DefaultExt = "xml"
                aFile.FileName = String.Format("TreeListLayout_{0}", Me.QueryName)
                aFile.AutoUpgradeEnabled = True
                If aFile.ShowDialog() = DialogResult.OK Then
                    TreeList1.SaveLayoutToXml(aFile.FileName)
                    MessageWindow.ShowMessage("Save Layout Successful", MsgBoxStyle.Information)
                End If
            End Using
            e.Handled = True 'TestPoint: Si on le met pas on peut passer 2 ou 3 fois selon le nombre de touche. aleblanc
        End If


        'Load Layout For the Focus View (from XML file on computer)
        If e.Control AndAlso e.Alt AndAlso e.KeyCode = Keys.G AndAlso TreeList1.Tag IsNot Nothing Then
            Using aFile As New System.Windows.Forms.OpenFileDialog
                aFile.DefaultExt = "xml"
                aFile.FileName = String.Format("TreeListLayout_{0}.xml", Me.QueryName)
                aFile.AutoUpgradeEnabled = True
                If aFile.ShowDialog() = DialogResult.OK Then
                    TreeList1.RestoreLayoutFromXml(aFile.FileName)
                End If
            End Using
            e.Handled = True 'TestPoint: Si on le met pas on peut passer 2 ou 3 fois selon le nombre de touche. aleblanc
        End If



        If e.Control And e.Alt And e.KeyCode = Keys.F Then
            Dim filteredColumns As List(Of DevExpress.XtraTreeList.Columns.TreeListColumn) = node.TreeList.Columns.Cast(Of DevExpress.XtraTreeList.Columns.TreeListColumn)().Where(Function(c) c.FilterInfo.AutoFilterRowValue IsNot Nothing).ToList()

            TreeList1.BeginUpdate()
            TreeList1.ActiveFilterString = ""


            TreeList1.TopVisibleNodeIndex = TreeList1.GetVisibleIndexByNode(node)
            TreeList1.EndUpdate()
            e.Handled = True
        End If




        If e.KeyCode = Keys.Enter Then
            Me.Cursor = Cursors.WaitCursor
            'Regle le bug du enter dans le filter row en jaune - Search en haut.
            If node.Selected = True Then
                NodeDataRow = TryCast(TreeList1.GetDataRecordByNode(node), DataRowView).Row
                PopulateDetailSection()
            End If
            Me.Cursor = Cursors.Default
        End If
    End Sub

    Public Overridable Sub ExplorerTreelist_PopupMenuShowing(sender As Object, e As DevExpress.XtraTreeList.PopupMenuShowingEventArgs) Handles TreeList1.PopupMenuShowing
        If NodeContextMenuBeforePopupEvent IsNot Nothing Then
            RaiseEvent NodeContextMenuBeforePopup(sender, e)
        End If
    End Sub


    Private Sub TreeList1_NodeCellStyle(sender As Object, e As DevExpress.XtraTreeList.GetCustomNodeCellStyleEventArgs) Handles TreeList1.NodeCellStyle
        If TreeList.AutoFilterNodeId = e.Node.Id Then
            e.Appearance.BackColor = Color.LightGoldenrodYellow
            e.Appearance.Font = New Font(e.Appearance.Font, FontStyle.Bold)
        End If
    End Sub

    Private Sub TreeList1_ShownEditor(sender As Object, e As System.EventArgs) Handles TreeList1.ShownEditor
        Dim node As TreeListNode = TreeList1.FocusedNode
        If TreeList.AutoFilterNodeId = node.Id Then
            TreeList1.ActiveEditor.Properties.EditValueChangedFiringMode = DevExpress.XtraEditors.Controls.EditValueChangedFiringMode.Buffered
        End If
    End Sub

    Private Sub TreeList1_GetStateImage(sender As Object, e As GetStateImageEventArgs) Handles TreeList1.GetStateImage
        e.NodeImageIndex = GetStateImageIndex(e.Node)
    End Sub

    Private Sub TreeList1_GetSelectImage(sender As Object, e As GetSelectImageEventArgs) Handles TreeList1.GetSelectImage

    End Sub

    Private Function GetStateImageIndex(ByVal node As TreeListNode) As Integer
        If Not IsDBNull(node.Item("Class")) Then
            Dim ClassimageName As String = node.Item("Class").ToString
            Dim ClassImageFilePath As String = IO.Path.Combine(Windows.Forms.Application.StartupPath, String.Format("Resources\{0}.png", ClassimageName))

        End If


        Dim imageName As String = node.Item("MetaQuerie").ToString
        Dim ImageFilePath As String = IO.Path.Combine(Windows.Forms.Application.StartupPath, String.Format("Resources\{0}.png", imageName))
        '
        'On ajoute les 2 images par defauts s'il n'y a rien dans la collection
        If ImageCollection1.Images.Count <= 0 Then
            ImageCollection1.AddImage(Image.FromFile(IO.Path.Combine(Windows.Forms.Application.StartupPath, "Resources\folder_closed.png")), "folder_close")
            ImageCollection1.AddImage(Image.FromFile(IO.Path.Combine(Windows.Forms.Application.StartupPath, "Resources\folder.png")), "folder_open")
        End If
        '

        If IO.File.Exists(ImageFilePath) Then
            If Not ImageCollection1.Images.Contains(ImageCollection1.Images(imageName)) Then
                'On ajoute si l'image existe sur la machine et que ce n'est pas deja dans la collection
                ImageCollection1.AddImage(Image.FromFile(ImageFilePath), imageName)
            End If
        Else
            'Comme l'image n'existe pas sur la machine, on y va avec les image par defaut selon le expand.
            If node.Expanded Then
                imageName = "folder_open"
            Else
                imageName = "folder_close"
            End If
        End If

        Return ImageCollection1.Images.IndexOf(ImageCollection1.Images(imageName))
    End Function

    Private Sub TreeList1_FocusedNodeChanged(sender As Object, e As FocusedNodeChangedEventArgs) Handles TreeList1.FocusedNodeChanged
        Dim _oldnode As TreeListNode = e.OldNode
        Dim _currentnode As TreeListNode = e.Node
        CurrentFocusedNode = _currentnode
        FocusedNodeLevel = _currentnode.Level
        If TypeOf (_currentnode) Is DevExpress.XtraTreeList.Nodes.TreeListAutoFilterNode Then
            LastFocusedNode = _oldnode
        End If

        BuildBreadCrumb(e.Node)

    End Sub

    Private Sub BuildBreadCrumb(node As TreeListNode)
        Dim treelistCol As DevExpress.XtraTreeList.ViewInfo.VisibleColumnsList = TreeList1.VisibleColumns

        If Not treelistCol Is Nothing AndAlso treelistCol.Count > 0 Then


            Dim alevel As Integer = TreeList1.FocusedNode.Level
            Dim LastCrumb As String = ""
            If Not (TypeOf (node) Is DevExpress.XtraTreeList.Nodes.TreeListAutoFilterNode) Then
                If alevel = 0 Then
                    _BreadCrumb = node.RootNode.GetDisplayText(treelistCol(0).AbsoluteIndex)
                Else
                    For i As Integer = alevel To 0 Step -1
                        LastCrumb = ">" & node.GetDisplayText(treelistCol(0).AbsoluteIndex) & LastCrumb
                        node = node.ParentNode
                    Next
                    _BreadCrumb = LastCrumb.Remove(0, 1)
                End If
            End If

        End If
    End Sub
End Class
